#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

extern char** environ;

int my_execvp(const char* file, char* const argv[]) {
    if (strchr(file, '/')) {
        execve(file, argv, environ);
        return -1;
    }

    char* path_env = getenv("PATH");
    if (path_env == NULL) {
        fprintf(stderr, "PATH not found\n");
        return -1;
    }

    char* path_copy = strdup(path_env);
    char* dir = strtok(path_copy, ":");

    while (dir != NULL) {
        char full_path[1024];
        snprintf(full_path, sizeof(full_path), "%s/%s", dir, file);
        if (access(full_path, X_OK) == 0) {
            free(path_copy);
            execve(full_path, argv, environ);
            return -1;
        }
        dir = strtok(NULL, ":");
    }

    fprintf(stderr, "Command not found: %s\n", file);
    free(path_copy);
    return -1;
}

void execute_command(const char* cmd,
                     int is_first, int is_last,
                     int prev_fd, int pipefd[2],
                     const char* input_file,
                     const char* output_file,
                     int append_mode) {
    pid_t pid = fork();
    if (pid == 0) {
        // 子进程

        if (!is_first && prev_fd != -1) {
            dup2(prev_fd, STDIN_FILENO);
            close(prev_fd);
        }

        if (!is_last) {
            close(pipefd[0]);
            dup2(pipefd[1], STDOUT_FILENO);
            close(pipefd[1]);
        }

        if (is_first && input_file[0] != '\0') {
            int fd = open(input_file, O_RDONLY);
            if (fd < 0) {
                perror("open input failed");
                exit(1);
            }
            dup2(fd, STDIN_FILENO);
            close(fd);
        }

        if (is_last && output_file[0] != '\0') {
            int flags = O_WRONLY | O_CREAT | (append_mode ? O_APPEND : O_TRUNC);
            int fd = open(output_file, flags, 0644);
            if (fd < 0) {
                perror("open output failed");
                exit(1);
            }
            dup2(fd, STDOUT_FILENO);
            close(fd);
        }

        // 拆分参数（提前截断 < > >> 等）
        char cmd_copy[1024];
        strncpy(cmd_copy, cmd, sizeof(cmd_copy));
        char *redir = strpbrk(cmd_copy, "<>");
        if (redir) *redir = '\0';  // 截断重定向符后面的部分

        char *args[64];
        int j = 0;
        char *arg = strtok(cmd_copy, " ");
        while (arg) {
            args[j++] = arg;
            arg = strtok(NULL, " ");
        }
        args[j] = NULL;

        // 打印调试参数
        fprintf(stderr, "Running: ");
        for (int k = 0; k < j; ++k) fprintf(stderr, "[%s] ", args[k]);
        fprintf(stderr, "\n");

        // 内建命令
        if (args[0] && strcmp(args[0], "cd") == 0) {
            if (args[1] == NULL) {
                fprintf(stderr, "cd: missing operand\n");
            } else if (chdir(args[1]) != 0) {
                perror("cd failed");
            }
            exit(0);
        }

        my_execvp(args[0], args);
        perror("exec failed");
        exit(1);
    }
}

void run_shell() {
    char command[1024];

    while (1) {
        char cwd[1024];
        if (getcwd(cwd, sizeof(cwd)) != NULL)
            printf("[%s] myshell> ", cwd);
        else
            perror("getcwd failed");

        if (fgets(command, sizeof(command), stdin) == NULL)
            continue;
        if (command[strlen(command) - 1] == '\n')
            command[strlen(command) - 1] = '\0';
        if (strcmp(command, "exit") == 0)
            break;

        // 提取重定向信息
        char raw_command[1024];
        strcpy(raw_command, command);

        char input_file[128] = {0};
        char output_file[128] = {0};
        int append_mode = 0;

        char *input_pos = strchr(raw_command, '<');
        char *output_pos = strstr(raw_command, ">>");
        if (output_pos) append_mode = 1;
        else output_pos = strchr(raw_command, '>');

        if (input_pos) {
            char *tmp = input_pos + 1;
            while (*tmp == ' ') tmp++;
            sscanf(tmp, "%127s", input_file);
        }

        if (output_pos) {
            char *tmp = output_pos + (append_mode ? 2 : 1);
            while (*tmp == ' ') tmp++;
            sscanf(tmp, "%127s", output_file);
        }

        // 拆分管道命令
        char *cmds[10];
        int cmd_count = 0;
        char *token = strtok(command, "|");
        while (token && cmd_count < 10) {
            while (*token == ' ') token++;
            cmds[cmd_count++] = token;
            token = strtok(NULL, "|");
        }

        int prev_fd = -1;
        int pipefd[2];

        for (int i = 0; i < cmd_count; ++i) {
            if (i < cmd_count - 1 && pipe(pipefd) < 0) {
                perror("pipe failed");
                exit(1);
            }

            // 只调用一次 execute_command，内部 fork
            execute_command(cmds[i], i == 0, i == cmd_count - 1,
                            prev_fd, pipefd, input_file, output_file, append_mode);

            if (prev_fd != -1) close(prev_fd);
            if (i < cmd_count - 1) {
                close(pipefd[1]);
                prev_fd = pipefd[0];
            }
        }

        for (int i = 0; i < cmd_count; ++i) wait(NULL);
    }
}


